package com.codi.api.controller.h5;

import com.codi.api.security.UserUtil;
import com.codi.api.validation.AccountValidation;
import com.codi.api.validation.QueryValidation;
import com.codi.api.validation.TradeValidation;
import com.codi.base.cache.CacheUtil;
import com.codi.base.exception.BaseAppException;
import com.codi.base.log.annotation.Loggable;
import com.codi.base.util.EqualsUtil;
import com.codi.base.util.ExceptionUtil;
import com.codi.base.util.MoneyUtils;
import com.codi.base.util.StringUtil;
import com.codi.base.web.RequestUtils;
import com.codi.bus.constant.GlobalConstant;
import com.codi.bus.core.domain.FundCombination;
import com.codi.bus.core.domain.FundWarehouseTransfer;
import com.codi.bus.core.domain.User;
import com.codi.bus.core.domain.UserBank;
import com.codi.bus.core.fund.FundErrorConst;
import com.codi.bus.core.fund.enums.FundDividendChangeBizTypeEnum;
import com.codi.bus.core.fund.request.DividendChangeRequestDto;
import com.codi.bus.core.fund.request.PortfolioTransferRequestDto;
import com.codi.bus.core.fund.response.DividendChangeResult;
import com.codi.bus.core.fund.service.FundDividendService;
import com.codi.bus.core.resultModel.*;
import com.codi.bus.core.service.*;
import com.codi.bus.core.service.model.DealType;
import com.codi.bus.core.service.model.PortfolioModel;
import com.codi.bus.core.service.model.PortfolioTradeModel;
import com.codi.bus.core.service.model.ShareTypeModel;
import com.codi.bus.core.util.BaseResultUtil;
import com.codi.bus.core.vo.PortfolioSellLimitRequestVo;
import com.codi.bus.core.vo.PortfolioTradeSellVo;
import com.codi.bus.core.vo.SellVo;
import com.codi.bus.core.vo.SessionVo;
import com.codi.fcloud.ufx.hssale.query.AccountBankQuery;
import com.codi.message.constant.ErrorConstant;
import com.codi.message.util.MessageUtil;
import com.codi.trade.dto.HsAccoBankQueryDto;
import com.codi.trade.response.HsAccoBankQueryResponse;
import com.google.common.base.Strings;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @Author: zengxl
 * @Description: 资产相关控制类
 * @Date:2018/3/8 13:48
 */
@RestController
@Slf4j
@RequestMapping("/h5/assets")
public class H5AssetsController {
    @Autowired
    private RedisTemplate<String, String> stringRedisTemplate;
    @Autowired
    private QueryService queryService;
    @Autowired
    private UserService userService;
    @Autowired
    private FundCombinationService fundCombinationService;
    @Autowired
    private AccountBankQuery accountBankQuery;
    @Autowired
    private BankService bankService;
    @Autowired
    private QueryValidation queryValidation;
    @Autowired
    private WalletService walletService;
    @Autowired
    private FundWarehouseTransferService fundWarehouseTransferService;
    @Autowired
    private PortfolioTransferService portfolioTransferService;
    @Autowired
    private AccountValidation accountValidation;
    @Autowired
    private BranchBankService branchBankService;
    @Autowired
    private PortfolioService portfolioService;
    @Autowired
    private TradeValidation tradeValidation;
    @Resource(name = "tradeService")
    private TradeService tradeService;
    @Autowired
    private FundDividendService fundDividendService;
    @Autowired
    private ApplyRecordService applyRecordService;

    /**
     * 获取交易类型 点击分类按钮
     *
     * @return
     */
    @GetMapping("/record/type")
    @Loggable
    public BaseResult getType() {
        BaseResult baseResult = new BaseResult();
        List<DealType> dealType = applyRecordService.getType();
        baseResult.setResult(dealType);
        return baseResult;
    }

    /**
     * 交易记录详情
     *
     * @param allotNo
     * @return
     */
    @GetMapping("/fundRecordDetail")
    @Loggable
    public BaseResult fundRecordDetail(HttpServletRequest request, String allotNo) {
        BaseResult baseResult = null;
        Long userId = Long.valueOf(RequestUtils.getHeader(request, "userid"));
        try {
            baseResult = applyRecordService.queryFundDetail(userId, allotNo);
        } catch (Exception e) {
            ExceptionUtil.logError(log, "fundRecordDetail - Exception:", e);
        }
        return baseResult;
    }

    /**
     * 查询组合资产信息
     *
     * @author mifj
     */
    @GetMapping("/portfolio")
    @Loggable
    public BaseResult portfolio(HttpServletRequest request) {
        Long userId = Long.valueOf(RequestUtils.getHeader(request, "userid"));
        try {
            return queryService.queryPortfolioAssets(userId);
        } catch (Exception e) {
            log.error("h5接口:/h5/assets/portfolio 错误信息:{}", e.getMessage());
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 查询组合具体基金信息 组合资产详情
     *
     * @author mifj
     */
    @GetMapping("/portfolio/detail")
    @Loggable
    public BaseResult portfolioDetail(@RequestParam String portfolioCode, HttpServletRequest request) {
        Long userId = Long.valueOf(RequestUtils.getHeader(request, "userid"));
        PortfolioModel result = queryService.queryPortfolioFunds(userId, portfolioCode);
        FundCombination fundCombination = fundCombinationService.queryOne(portfolioCode);
        if (fundCombination != null && fundCombination.getAnnualizedIncome() != null) {
            result.setShare("向您推荐一只基金组合，组合年化收益率为" + fundCombination.getAnnualizedIncome().toString() + "%");
        } else {
            result.setShare("向您推荐一只基金组合");
        }
        if (!result.getSuccess() && StringUtil.isEmpty(result.getErrorMessage())) {
            result.setErrorMessage(MessageUtil.getErrorMessage(result.getErrorCode(), null));
        }
        // spy 2017-12-13 10:45:00
        if (result.getPortfolioTrades() != null) {
            // 查询用户银行卡列表
            User user = userService.getUser(userId);
            if (Strings.isNullOrEmpty(user.getExternalClientId())) {
                return result;
            }
            HsAccoBankQueryDto queryDto = HsAccoBankQueryDto.builder().client_id(user.getExternalClientId()).build();
            List<HsAccoBankQueryResponse> hsBanks = accountBankQuery.query(queryDto);
            if (hsBanks != null) {
                List<PortfolioTradeModel> portfolioTrades = result.getPortfolioTrades();
                portfolioTrades.forEach(item -> {
                    String portfolioTradeAcco = item.getTradeAcco();
                    for (HsAccoBankQueryResponse queryResponse : hsBanks) {
                        if (EqualsUtil.equals(portfolioTradeAcco, queryResponse.getTrade_acco())) {
                            List<UserBank> userBanks = bankService.getBanks(user.getUserId(), queryResponse.getBank_account());
                            if (userBanks == null || userBanks.isEmpty()) {
                                log.warn("h5接口:/h5/assets/portfolio/detail userId={},bankNo={}不存在", user.getUserId(), queryResponse.getBank_account());
                            } else {
                                UserBank userBank = userBanks.get(0);
                                item.setUserBankNo(userBank.getUserBankNo());
                                item.setBankCode(userBank.getBankCode());
                                item.setBankName(userBank.getBankName());
                                item.setBranchBank(userBank.getBranchbank() == null ? "" : userBank.getBranchbank());
                                item.setBranchBankName(userBank.getBankBranchName() == null ? "" : userBank.getBankBranchName());
                                item.setCapitalMode(userBank.getCapitalMode());
                            }
                            break;
                        }
                    }
                });
            } else {
                log.warn("h5接口:/h5/assets/portfolio/detail 错误信息:没有该账户对应的银行卡交易账号信息");
            }
        }
        return result;
    }


    /**
     * 查询资产，过滤掉T0基金和组合
     *
     * @param requestNum    请求行数
     * @param queryFlag     0-不重新统计；1-重新统计； 建议传1
     * @param beginNum      查询起始行号
     * @param sortDirection 返回排序方式
     * @author mifj
     */
    @GetMapping("/fund")
    @Loggable
    public BaseResult shareQuery(@RequestParam Integer requestNum,
                                 @RequestParam Integer queryFlag,
                                 @RequestParam Integer beginNum,
                                 @RequestParam String sortDirection, HttpServletRequest request) {
        // 验证输入
        ShareListResult result = queryValidation.validateShareQuery(requestNum);
        if (result != null) {
            return result;
        }
        Long userId = Long.valueOf(RequestUtils.getHeader(request, "userid"));
        result = queryService.querySharesWithoutPort(userId, requestNum, queryFlag, beginNum,
            sortDirection, true);
        if (!result.getSuccess() && StringUtil.isEmpty(result.getErrorMessage())) {
            result.setErrorMessage(MessageUtil.getErrorMessage(result.getErrorCode(), null));
        }
        return result;
    }

    /**
     * 瑞富宝资产
     *
     * @author mifj
     */
    @GetMapping("/ruifubao")
    @Loggable
    public WalletDetailResultV2 ruifubao(HttpServletRequest request) throws BaseAppException {
        Long userId = Long.valueOf(RequestUtils.getHeader(request, "userid"));
        return walletService.getWalletDetailV2(userId);
    }

    /**
     * 资产--组合资产调仓
     *
     * @param transferId
     * @return
     */
    @GetMapping("portfolio/goTransfer")
    @Loggable
    public BaseResult portfolioGoTransfer(@RequestParam String transferId) {
        BaseResult result = new BaseResult();
        result.setSuccess(false);
        if (StringUtil.isEmpty(transferId)) {
            result.setErrorCode(ErrorConstant.ERROR_FIELD_NO_FIND);
            Map<String, String> map = new HashMap<>();
            map.put(ErrorConstant.PLACEHOLDER_FIELD_NO_FIND_FIELD, "调仓记录主键");
            result.setErrorMessage(MessageUtil.getErrorMessage(ErrorConstant.ERROR_FIELD_NO_FIND, map));
            return result;
        }
        FundWarehouseTransfer fundWarehouseTransfer = fundWarehouseTransferService.selectOne(Long.valueOf(transferId));
        if (fundWarehouseTransfer == null) {
            result.setErrorCode(FundErrorConst.PORTFOLIO_TRANSFER_NOT_EXIST);
            result.setErrorMessage(MessageUtil.getErrorMsg(FundErrorConst.PORTFOLIO_TRANSFER_NOT_EXIST));
            return result;
        }
        result.setSuccess(true);
        result.setResult(fundWarehouseTransfer.getTransferContent());
        return result;
    }

    /**
     * 资产--组合资产确认调仓
     *
     * @param request
     * @param dto
     * @return
     */
    @PostMapping("portfolio/sureTransfer")
    @Loggable
    public BaseResult portfolioSureTransfer(HttpServletRequest request, @Validated PortfolioTransferRequestDto dto) {
        Long userId = Long.valueOf(RequestUtils.getHeader(request, "userid"));
        dto.setUserId(userId);
        return portfolioTransferService.transfer(dto);
    }

    /**
     * 资产--组合资产持有赎回
     *
     * @param request
     * @return
     */
    @PostMapping("portfolio/withdraw")
    @Loggable
    public PortfolioSellLimitResult portfolioWithdraw(HttpServletRequest request, @Validated @RequestBody PortfolioSellLimitRequestVo vo) {
        Long userId = Long.valueOf(RequestUtils.getHeader(request, "userid"));
        vo.setUserId(userId);
        vo.setCaptialMode(GlobalConstant.CAPITAL_MODE_EPAY);
        return portfolioService.getSellLimits(vo);
    }

    /**
     * 资产--组合资产持有确认赎回
     *
     * @param request
     * @param sellVo
     * @param vcBranchbank
     * @param vcBankname
     * @return
     */
    @PostMapping("portfolio/sureWithdraw")
    @Loggable
    public BaseResult portfolioSureWithdraw(HttpServletRequest request, @Validated PortfolioTradeSellVo sellVo, @RequestParam String vcBranchbank, @RequestParam String vcBankname) {
        BaseResult result = new BaseResult();
        if (StringUtil.isEmpty(sellVo.getTradePassword())) {
            result.setErrorCode(ErrorConstant.ERROR_FIELD_NO_FIND);
            Map<String, String> map = new HashMap<>();
            map.put(ErrorConstant.PLACEHOLDER_FIELD_NO_FIND_FIELD, "交易密码");
            result.setErrorMessage(MessageUtil.getErrorMessage(ErrorConstant.ERROR_FIELD_NO_FIND, map));
            return result;
        }
        if (StringUtil.isEmpty(sellVo.getInnerPortfolioCode())) {
            result.setErrorCode(ErrorConstant.ERROR_FIELD_NO_FIND);
            Map<String, String> map = new HashMap<>();
            map.put(ErrorConstant.PLACEHOLDER_FIELD_NO_FIND_FIELD, "组合编码");
            result.setErrorMessage(MessageUtil.getErrorMessage(ErrorConstant.ERROR_FIELD_NO_FIND, map));
            return result;
        }
        if (StringUtil.isEmpty(sellVo.getPortfolioTradeAcco())) {
            result.setErrorCode(ErrorConstant.ERROR_FIELD_NO_FIND);
            Map<String, String> map = new HashMap<>();
            map.put(ErrorConstant.PLACEHOLDER_FIELD_NO_FIND_FIELD, "组合的交易账号");
            result.setErrorMessage(MessageUtil.getErrorMessage(ErrorConstant.ERROR_FIELD_NO_FIND, map));
            return result;
        }
        Long userId = Long.valueOf(RequestUtils.getHeader(request, "userid"));
        String chanelCode = RequestUtils.getHeader(request, "channelCode");

        // 验证是否重复提交, 5分钟过期
        String applyNo = sellVo.getApplyNo() + userId;
        String applyKey = CacheUtil.getKey(GlobalConstant.REDIS_KEY_APPLY_SELL, applyNo);
        if (!StringUtil.isEmpty(stringRedisTemplate.opsForValue().get(applyKey))) {
            result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
            result.setErrorCode(ErrorConstant.ERROR_DUPLICATE_APPLY);
            result.setErrorMessage(MessageUtil.getErrorMessage(ErrorConstant.ERROR_DUPLICATE_APPLY, null));
            return result;
        }
        stringRedisTemplate.opsForValue().set(applyKey, applyNo, GlobalConstant.APPLY_EXPIRED_HOURS_DEFAULT, TimeUnit.HOURS);

        //支行修改
        BaseResult resultV = null;
        resultV = accountValidation.setBranchBankValidate(vcBranchbank, sellVo.getTradePassword());
        if (resultV != null) {
            return resultV;
        }
        resultV = branchBankService.setBranchBank(userId, vcBranchbank, vcBankname, sellVo.getTradePassword());
        if (!resultV.getSuccess()) {
            return resultV;
        }
        SessionVo sessionVo = new SessionVo();
        sessionVo.setUserId(userId)
            .setChannelId(chanelCode);
        return portfolioService.sell38(sessionVo, sellVo);
    }

    /**
     * 资产--基金持有赎回
     *
     * @param request
     * @param fundCode
     * @return
     */
    @GetMapping("fund/withdraw")
    @Loggable
    public TradeLimitListResult fundWithdraw(HttpServletRequest request, @RequestParam String fundCode) {
        TradeLimitListResult result = new TradeLimitListResult();
        result.setSuccess(false);
        if (StringUtil.isEmpty(fundCode)) {
            result.setErrorCode(ErrorConstant.ERROR_FIELD_NO_FIND);
            Map<String, String> map = new HashMap<>();
            map.put(ErrorConstant.PLACEHOLDER_FIELD_NO_FIND_FIELD, "基金代码");
            result.setErrorMessage(MessageUtil.getErrorMessage(ErrorConstant.ERROR_FIELD_NO_FIND, map));
            return result;
        }
        ShareTypeModel shareTypeModel = queryService.getShareType(fundCode);
        if (shareTypeModel == null || StringUtil.isEmpty(shareTypeModel.getShareType())) {
            result.setSuccess(false);
            result.setErrorCode(ErrorConstant.ERROR_NO_SHARE_TYPE_FIND);
            result.setErrorMessage(MessageUtil.getErrorMessage(ErrorConstant.ERROR_NO_SHARE_TYPE_FIND, null));
            return result;
        }
        Long userId = Long.valueOf(RequestUtils.getHeader(request, "userid"));
        String shareType = shareTypeModel.getShareType();
        User user = userService.getUser(userId);
        String custType = user.getIsOrg() ? GlobalConstant.CUST_TYPE_ORGANIZATION : GlobalConstant.CUST_TYPE_PERSONAL;
        //String capitalMode = user.getIsOrg()?GlobalConstant.CAPITAL_MODE_EPAY:GlobalConstant.CAPITAL_MODE_EPAY;
        result = queryService.queryTradeLimits(GlobalConstant.MAX_REQUEST_NUM, 1, 1, "1", fundCode, shareType,
            GlobalConstant.CAPITAL_MODE_EPAY, "024", custType);
        if (result.getSuccess() == false && StringUtil.isEmpty(result.getErrorMessage())) {
            result.setErrorMessage(MessageUtil.getErrorMessage(result.getErrorCode(), null));
        }
        return result;
    }

    /**
     * 资产--基金持有确认赎回
     *
     * @param request
     * @param bankAccount   银行账号
     * @param fundName      基金名称
     * @param fundCode      基金代码
     * @param shares        赎回份额
     * @param tradePassword 交易密码
     * @param applyNo       自动生成，格式：yyyyMMddHHmmssSSS
     * @param vcBranchbank  支行编码
     * @param vcBankname    支行名称
     * @return
     */
    @PostMapping("fund/sureWithdraw")
    @Loggable
    public BaseResult fundSureWithdraw(HttpServletRequest request, @RequestParam String bankAccount, @RequestParam String fundName,
                                       @RequestParam String fundCode, @RequestParam BigDecimal shares, @RequestParam String tradePassword, @RequestParam String applyNo, @RequestParam String vcBranchbank,
                                       @RequestParam String vcBankname) {
        Long userId = Long.valueOf(RequestUtils.getHeader(request, "userid"));
        String paymentType = GlobalConstant.CAPITAL_MODE_EPAY;
        BaseResult result = null;
        result = tradeValidation.baseValidate(bankAccount, paymentType, fundName, fundCode, tradePassword);
        if (result != null) {
            return result;
        }
        result = new BaseResult();
        // 如果两个数一样则返回0，如果第一个数比第二个数大则返回1，反之返回-1
        if (MoneyUtils.compareTo(shares, 0) != 1) {
            result.setSuccess(false);
            result.setErrorCode(ErrorConstant.ERROR_FIELD_NO_FIND);
            Map<String, String> map = new HashMap<>();
            map.put(ErrorConstant.PLACEHOLDER_FIELD_NO_FIND_FIELD, "赎回份额");
            result.setErrorMessage(MessageUtil.getErrorMessage(ErrorConstant.ERROR_FIELD_NO_FIND, map));
            return result;
        }
        // 验证是否重复提交, 5分钟过期
        applyNo = applyNo + userId;
        String applyKey = CacheUtil.getKey(GlobalConstant.REDIS_KEY_APPLY_SELL, applyNo);
        if (!StringUtil.isEmpty(stringRedisTemplate.opsForValue().get(applyKey))) {
            result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
            result.setErrorCode(ErrorConstant.ERROR_DUPLICATE_APPLY);
            result.setErrorMessage(MessageUtil.getErrorMessage(ErrorConstant.ERROR_DUPLICATE_APPLY, null));
            return result;
        }
        stringRedisTemplate.opsForValue().set(applyKey, applyNo, GlobalConstant.APPLY_EXPIRED_HOURS_DEFAULT, TimeUnit.HOURS);
        //支行修改
        BaseResult resultV = null;
        resultV = accountValidation.setBranchBankValidate(vcBranchbank, tradePassword);
        if (resultV != null) {
            return resultV;
        }
        resultV = branchBankService.setBranchBank(userId, vcBranchbank, vcBankname, tradePassword);
        if (!resultV.getSuccess()) {
            return resultV;
        }
        // 获取份额类别
        ShareTypeModel shareTypeModel = queryService.getShareType(fundCode);
        if (shareTypeModel == null || StringUtil.isEmpty(shareTypeModel.getShareType())) {
            result.setSuccess(false);
            result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
            result.setErrorCode(ErrorConstant.ERROR_NO_SHARE_TYPE_FIND);
            result.setErrorMessage(MessageUtil.getErrorMessage(ErrorConstant.ERROR_NO_SHARE_TYPE_FIND, null));
            return result;
        }

        // 获取份额类别
        String shareType = shareTypeModel.getShareType();
        String chanelCode = RequestUtils.getHeader(request, "channelCode");

        // 调用接口
        result = tradeService.sellReal(userId, chanelCode, bankAccount, paymentType, fundName, fundCode,
            shares, shareType, tradePassword, applyNo);
        if (result.getSuccess() == false && StringUtil.isEmpty(result.getErrorMessage())) {
            result.setErrorMessage(MessageUtil.getErrorMessage(result.getErrorCode(), null));
        }
        return result;


    }

    /**
     * 赎回普通基金转购 瑞富宝
     *
     * @return
     * @author zx
     * @date 2018-05-07 14:10:15
     */
    @Loggable
    @PostMapping("/sellForWallet")
    @ResponseBody
    public BaseResult sellForWallet(@Validated SellVo sellVo,HttpServletRequest request) {
        Long userId = Long.valueOf(RequestUtils.getHeader(request,"userid"));

        sellVo.setUserId(userId);
        String chanelCode = RequestUtils.getHeader(request, "channelCode");
        sellVo.setChannelId(chanelCode);
        sellVo.setMoneyType(GlobalConstant.MONEY_TYPE_RMB);

        BaseResult result;

        // 验证输入
//        result = tradeValidation.validateSellForWallet(sellVo);
//        if (result != null) {
//            logger.info("trade validation fail.");
//            return result;
//        }

        // 调用接口
        result = tradeService.sellForWallet(sellVo);

        BaseResultUtil.parseErrMsg(result);

        return result;
    }

    /**
     * 资产--基金--保存修改分红方式
     *
     * @param request
     * @param dto
     * @return
     */
    @PostMapping("saveFundBonus")
    @Loggable
    public DividendChangeResult saveFundBonus(HttpServletRequest request, @Validated DividendChangeRequestDto dto) {
        Long userId = Long.valueOf(RequestUtils.getHeader(request, "userid"));
        dto.setUserId(userId);
        dto.setBizType(FundDividendChangeBizTypeEnum.COMMON.getKey());
        return fundDividendService.change(dto);
    }
}
